#include "sceneModel.h"
#include "objects/crate.h"
#include "objects/clamp.h"
#include "objects/truck.h"
#include "objects/rain.h"
#include "objects/tree.h"
#include "objects/skyBox.h"
#include "objects/helix.h"
#include "objects/rotor.h"
#include "objects/thread.h"
#include "objects/warehouse.h"
#include "objects/boxPlatform.h"
#include "objects/light_post.h"
#include "lighting.h"
#include "model/objectModel/fileModel.h"
#include <algorithm>
#include <cassert>

const std::string SceneModel::modelPath = "./modelos/";

SceneModel::SceneModel()
		:	gravity(-0.3f) {
	currentEnvironState = NO_ENVIRON;
	this->setEnviron(DAY_ENVIRON);
}

SceneModel::~SceneModel() {
	for(std::vector<SceneObject*>::iterator it=objectList.begin();it!=objectList.end();++it){
		delete *it;
	}
}

void SceneModel::clearObjects(){
	for(std::vector<SceneObject*>::iterator it=objectList.begin();it!=objectList.end();++it){
		delete *it;
	}

	objectList.clear();
	indices.clear();
	gravity.clear();
}

Ground& SceneModel::getGround(){
	return *this->ground;
}

Truck& SceneModel::getTruck(){
	return *this->truck;
}

Watcher& SceneModel::getWatcher(){
	return this->watcher;
}

Cube& SceneModel::getSceneCube(){
	return this->sceneCube;
}

Helicopter& SceneModel::getHelicopter(){
	return *this->helicopter;
}

Rain& SceneModel::getRain(){
	return *this->rain;
}

SkyBox& SceneModel::getSkyBox(){
	return *this->sbox;
}

void SceneModel::timer(int value){
	gravity.advanceTime();

	for(std::vector<SceneObject*>::iterator it=objectList.begin();it!=objectList.end();++it){
		(*it)->timeStep();
	}

	if(clamp->isClosed() && clamp->getGrabbed()){
		Crate* grabbed = static_cast<Crate*>(clamp->getGrabbed());
		/*std::vector<SceneObject*>::iterator it = std::find(objectList.begin(),objectList.end(),grabbed);
		assert(it!=objectList.end());
		objectList.erase(it);*/
		gravity.removeSolid(grabbed);
		grabbed->setGrabbed(true);
	}

	limitHelicopter();
}


void SceneModel::limitHelicopter(){
	Point heliCenter = helicopter->getDimensions().center();

	if(heliCenter.x1 < sceneCube.minX()){
		helicopter->setSpeed(Point(0,0,0));
		helicopter->move(sceneCube.minX()-heliCenter.x1,0,0);
	}
	else if(heliCenter.x1 > sceneCube.maxX()){
		helicopter->setSpeed(Point(0,0,0));
		helicopter->move(sceneCube.maxX()-heliCenter.x1,0,0);
	}

	if(heliCenter.x3 > sceneCube.maxZ()){
		helicopter->setSpeed(Point(0,0,0));
		helicopter->move(0,0,-heliCenter.x3+sceneCube.maxZ());
	}
	else if(heliCenter.x3 < 5.0f){
		helicopter->setSpeed(Point(0,0,0));
		helicopter->move(0,0,5.0f-heliCenter.x3);
	}


	if(heliCenter.x2 < sceneCube.minY()){
		helicopter->setSpeed(Point(0,0,0));
		helicopter->move(0,sceneCube.minY()-heliCenter.x2,0);
	}else if(heliCenter.x2 > sceneCube.maxY()){
		helicopter->setSpeed(Point(0,0,0));
		helicopter->move(0,sceneCube.maxY()-heliCenter.x2,0);
	}
}

void SceneModel::handleClamp(){
    if (clamp->isClosed()){
		clamp->open();
		if(clamp->getGrabbed()){
			 Crate* grabbed = static_cast<Crate*>(clamp->release());
			 clamp->getObject(Grabable::name());
			 grabbed->setParent(NULL);
			 objectList.push_back(grabbed);
			 gravity.addSolid(grabbed);
			 grabbed->setGrabbed(false);
		}
     }else{
    	 clamp->close();
     }
}

void SceneModel::initSceneObjects(){
	this->clearObjects();

	if(this->getEnvironState()==MNT_ENVIRON){
		this->sceneCube = Cube(Point(0,0,0),Point(512,512,100));
		watcher.setWatcherPosition(Point(225.0f,311.0f,2.0));
	}else{
		this->sceneCube = Cube(Point(0,0,0),Point(612,612,50));
		watcher.setWatcherPosition(Point(256.0f,256.0f,2.0));
	}

	// !! DEBE SER EL PRIMERO SIEMPRE DADO QUE DESHABILITA EL DEPTH TEST
	this->createSkyBox();

	this->createGround();
	this->createHelicopter();
	this->createTruck();
	this->createPlatform();
	this->createCrates();
	this->createTrees();
	this->createWarehouse();
	this->createLightPosts();

	if(this->getEnvironState()==STORM_ENVIRON)
		this->createRain();
}

void SceneModel::createRain(){
	FileModel* fmodel = new FileModel(modelPath+"rain/","drop.obj");
	fmodel->loadModel();
	SceneObject::ObjectModelPtr modelPtr(fmodel);

	FileModel* lightingModel = new FileModel(modelPath+"rain/","lightning.obj");
	lightingModel->loadModel();
	SceneObject::ObjectModelPtr lightingModelPtr(lightingModel);

	Cube rainCube(Point(-10,-10,9),Point(10,10,50));
	Point sceneCenter = this->sceneCube.center();
	sceneCenter.x3 = 0;
	rain = new Rain(rainCube,2,sceneCenter,gravity,modelPtr,lightingModelPtr);

	std::map<std::string,unsigned int>::iterator it=indices.find(Rain::name());
	if(it==indices.end()){
		this->objectList.push_back(rain);
		indices.insert(std::make_pair(Rain::name(),this->objectList.size()-1));
	}else{
		// Borro el que ya esta y pongo el nuevo
		delete this->objectList[it->second];
		this->objectList[it->second] = rain;
	}
}

void SceneModel::createCrates(){
	const unsigned int boxToCreate = 10;
	const unsigned int boxTypes = 7;
	const unsigned int boxSizesCount = 3;
	Cube platformCube = this->objectList[this->indices[BoxPlatform::name()]]->getDimensions();

	const Cube boxSizes[] = {	Cube(Point(0,0,0),Point(1.8,1.8,1)),
								Cube(Point(0,0,0),Point(2,2,2)),
								Cube(Point(0,0,0),Point(1.5,1.5,1.5)) };


	// El helicoptero debe estar ya creado
	if(indices.find(Helicopter::name())==indices.end())
		throw SceneModelException("No se pueden crear las cajas antes que el helicoptero");

	std::vector<Cube> createdCubes;
	for(unsigned int c=0;c<boxToCreate;c++){
		unsigned int type = (rand()%boxTypes+1);
		std::ostringstream path;
		std::ostringstream fname;
		std::ostringstream name;
		path << modelPath << "crates/crate_" << type << "/";
		fname << "crate_" << type << ".obj";

		FileModel* fmodel = new FileModel(path.str(),fname.str());
		fmodel->loadModel();
		SceneObject::ObjectModelPtr modelPtr(fmodel);

		Cube cube;
		bool collide=false;
		do{
			cube = boxSizes[rand()%boxSizesCount];
			float x = rand()%(int)platformCube.width() + platformCube.minX();
			float y = rand()%(int)platformCube.depth() + platformCube.minY();
			float z = rand()%(20) + platformCube.maxZ()+20.0f;
			cube.translate(x,y,z);

			// Esta caja creada no debe colisionar con ninguna otra
			collide=false;
			for(std::vector<Cube>::iterator it=createdCubes.begin();it!=createdCubes.end()&&!collide;it++)
				collide = it->intersect(cube);
		}while(collide);

		Crate* crate = new Crate(cube,Point(0,1,0),modelPtr);
		createdCubes.push_back(cube);

		name << Crate::name() << c;
		std::map<std::string,unsigned int>::iterator it=indices.find(name.str());
		if(it==indices.end()){
			this->objectList.push_back(crate);
			indices.insert(std::make_pair(name.str(),this->objectList.size()-1));
		}else{
			// Borro el que ya esta y pongo el nuevo
			clamp->removeGrabable(dynamic_cast<Grabable*>(this->objectList[it->second]));
			gravity.removeSolid(dynamic_cast<Solid*>(this->objectList[it->second]));
			delete this->objectList[it->second];
			this->objectList[it->second] = crate;
		}

		gravity.addSolid(crate);

		clamp = helicopter->getClamp();
		clamp->addGrabable(crate);
	}

	//DebugCrate
	FileModel* dfmodel = new FileModel(modelPath+"crates/crate_1/","crate_1.obj");
	dfmodel->loadModel();
	SceneObject::ObjectModelPtr dmodelPtr(dfmodel);


	Cube dcube = boxSizes[1];
	if(this->getEnvironState()==MNT_ENVIRON)
		dcube.center(Point(226.0f,311.0f,60.0f));
	else
		dcube.translate(252,233,60.0f);
	Crate* dcrate = new Crate(dcube,Point(0,1,0),dmodelPtr);

	this->objectList.push_back(dcrate);

	gravity.addSolid(dcrate);

	clamp = helicopter->getClamp();
	clamp->addGrabable(dcrate);
}

void SceneModel::createHelicopter(){
	FileModel* fmodel = new FileModel(modelPath,"cube.obj");
	fmodel->loadModel();
	SceneObject::ObjectModelPtr modelPtr(fmodel);

	FileModel* clampModel = new FileModel(modelPath+"clamp/","clamp.obj");
	clampModel->loadModel();
	SceneObject::ObjectModelPtr clampModelPtr(clampModel);

	FileModel* threadModel = new FileModel(modelPath+"clamp/","thread.obj");
	threadModel->loadModel();
	SceneObject::ObjectModelPtr threadModelPtr(threadModel);

	FileModel* clampSideBModel = new FileModel(modelPath+"clamp/","clamp_side_b.obj");
	clampSideBModel->loadModel();
	SceneObject::ObjectModelPtr clampSideBModelPtr(clampSideBModel);


	Cube helicopterCube(Point(0,3,0),Point(11,14,11));
	helicopterCube.center(Point(224,310,20));

	FileModel* helicopterModel = new FileModel(modelPath + "helicopter/","helicopter.obj");
	helicopterModel->loadModel();
	SceneObject::ObjectModelPtr helicopterModelPtr(helicopterModel);

	FileModel* topHelixModel = new FileModel(modelPath + "helicopter/","top_helix.obj");
	topHelixModel->loadModel();
	SceneObject::ObjectModelPtr topHelixModelPtr(topHelixModel);

	FileModel* rotorModel = new FileModel(modelPath + "helicopter/","rotor.obj");
	rotorModel->loadModel();
	SceneObject::ObjectModelPtr rotorModelPtr(rotorModel);

	std::map<std::string,SceneObject::ObjectModelPtr> helicopterModels;
	helicopterModels.insert(std::make_pair(Helicopter::name(),helicopterModelPtr));
	helicopterModels.insert(std::make_pair(Rotor::name(),rotorModelPtr));
	helicopterModels.insert(std::make_pair(Helix::name(),topHelixModelPtr));
	helicopterModels.insert(std::make_pair(Thread::name(),threadModelPtr));
	helicopterModels.insert(std::make_pair(Clamp::name(),clampModelPtr));
	helicopterModels.insert(std::make_pair(ClampSideA::name(),clampSideBModelPtr));
	helicopterModels.insert(std::make_pair(ClampSideB::name(),clampSideBModelPtr));
	helicopter = new Helicopter(helicopterCube, Point(0,1,0),helicopterModels);
	clamp = helicopter->getClamp();

	std::map<std::string,unsigned int>::iterator it=indices.find(Helicopter::name());
	if(it==indices.end()){
		this->objectList.push_back(helicopter);
		indices.insert(std::make_pair(Helicopter::name(),this->objectList.size()-1));
	}else{
		delete this->objectList[it->second];
		this->objectList[it->second] = helicopter;
	}
}

void SceneModel::createTruck(){
	Path* path = new Path();

	Cube chasisCube(Point(0,3,-2.25),Point(8,10,4.75));
	Cube loadAreaCube(Point(0.15,-0.45,0.2f),Point(-0.16,-0.05,0.4));
	Point dir(0,1,0);

	TruckPathInfo* loadPathInfo;
	TruckPathInfo* unloadPathInfo;
	if(this->getEnvironState()==MNT_ENVIRON){
		chasisCube.center(Point(227.15f,313.677f,3.1));
		parsePathFile(*path,modelPath+"camioneta/mnt_path.data",loadPathInfo,unloadPathInfo);
	}else{
		chasisCube.translate(250,230,0);
		parsePathFile(*path,modelPath+"camioneta/path.data",loadPathInfo,unloadPathInfo);
	}

	FileModel* truckModel = new FileModel(modelPath + "camioneta/","camioneta.obj");
	truckModel->loadModel();
	SceneObject::ObjectModelPtr truckModelPtr(truckModel);

	FileModel* tireModel = new FileModel(modelPath + "camioneta/","tire.obj");
	tireModel->loadModel();
	SceneObject::ObjectModelPtr tireModelPtr(tireModel);

	FileModel* loadAreaModel = new FileModel(modelPath,"cube.obj");
	loadAreaModel->loadModel();
	SceneObject::ObjectModelPtr loadAreaModelPtr(loadAreaModel);

	truck = new Truck(chasisCube,loadAreaCube,dir,path,truckModelPtr,tireModelPtr,loadAreaModelPtr);

	TruckPathInfo::PathNotifyCallbackType unloadCallback = std::tr1::bind(	&Truck::unloadAreaReached,truck,std::tr1::placeholders::_1);
	TruckPathInfo::PathNotifyCallbackType loadCallback = std::tr1::bind(	&Truck::loadAreaReached,truck,std::tr1::placeholders::_1);
	unloadPathInfo->setCallback(unloadCallback);
	loadPathInfo->setCallback(loadCallback);

	std::map<std::string,unsigned int>::iterator it=indices.find(Truck::name());
	if(it==indices.end()){
		this->objectList.push_back(truck);
		indices.insert(std::make_pair(Truck::name(),this->objectList.size()-1));
	}else{
		gravity.removeSolid(dynamic_cast<Solid*>(this->objectList[it->second]));
		delete this->objectList[it->second];
		this->objectList[it->second]=truck;
	}

	gravity.addSolid(truck);
}

void SceneModel::createSkyBox(){
	//Cube sboxCube(Point(0,0,-250),Point(900,900,350));
	//Cube sboxCube(Point(0,0,-200),Point(900,900,300));
	Cube sboxCube(Point(0,0,-200),Point(900,900,300));

	FileModel* sboxModel;
	EnvironState environ = this->getEnvironState();
	if(environ==DAY_ENVIRON)
		sboxModel = new FileModel(modelPath+"skybox/","skybox_day.obj");
	else if(environ==SUNSET_ENVIRON)
		sboxModel = new FileModel(modelPath+"skybox/","skybox_sunset.obj");
	else if(environ==NIGHT_ENVIRON)
		sboxModel = new FileModel(modelPath+"skybox/","skybox_night.obj");
	else if(environ==STORM_ENVIRON)
		sboxModel = new FileModel(modelPath+"skybox/","skybox_storm.obj");
	else if(environ==MNT_ENVIRON)
		sboxModel = new FileModel(modelPath+"skybox/","skybox_mnt.obj");

	sboxModel->loadModel();
	SceneObject::ObjectModelPtr sboxModelPtr(sboxModel);
	sbox = new SkyBox(sboxCube,sboxModelPtr);

	std::map<std::string,unsigned int>::iterator it=indices.find(SkyBox::name());
	if(it==indices.end()){
		this->objectList.push_back(sbox);
		indices.insert(std::make_pair(SkyBox::name(),this->objectList.size()-1));
	}else{
		delete this->objectList[it->second];
		this->objectList[it->second]=sbox;
	}
}

void SceneModel::createGround(){
	FileModel* groundModel;


	float tileWidth,tileHeight;
	unsigned int rows,cols;
	EnvironState environ = this->getEnvironState();
	if(environ==MNT_ENVIRON){
		tileWidth = tileHeight = 4.0f;
		cols = rows = 128;
		groundModel = new FileModel(modelPath+"ground/","ground_dirty.obj");
	}else{
		tileWidth = tileHeight = 12.0f;
		cols = rows = 51;
		groundModel = new FileModel(modelPath+"ground/","ground_green.obj");
	}
	Cube c2(Point(0,0,-0.3),Point(cols*tileWidth,rows*tileHeight,0));

	groundModel->loadModel();
	SceneObject::ObjectModelPtr groundModelPtr(groundModel);


	ground = new Ground(c2,Point(0,1,0),groundModelPtr);
	ground->tileWidth(tileWidth);
	ground->tileHeight(tileHeight);
	ground->cols(cols);
	ground->rows(rows);

	std::map<std::string,unsigned int>::iterator it=indices.find(Ground::name());
	if(it==indices.end()){
		this->objectList.push_back(ground);
		indices.insert(std::make_pair(Ground::name(),this->objectList.size()-1));
	}else{
		gravity.removeSolid(dynamic_cast<Solid*>(this->objectList[it->second]));
		delete this->objectList[it->second];
		this->objectList[it->second]=ground;
	}

	gravity.addSolid(ground);
}

void SceneModel::setEnviron(EnvironState state){

	if(state==currentEnvironState)
		return;
	if(currentEnvironState==NO_ENVIRON)
		createEnvironLights();

	currentEnvironState = state;
	initSceneObjects();
	watcher.ground(dynamic_cast<Ground*>(this->objectList[this->indices[Ground::name()]]));

	// se apagan todas las luces
	for(std::map<EnvironState,std::vector<Light*> >::iterator it=lights.begin();it!=lights.end();++it){
		for(std::vector<Light*>::iterator it2=it->second.begin();it2!=it->second.end();++it2){
			(*it2)->disable();
		}
	}

	for(unsigned int c=0;c<lights[state].size();c++){
		lights[state][c]->enable();
	}

	if(state==DAY_ENVIRON){
		// dia
		Lighting::instance().globalAmbient(RGBAColor(0.2f, 0.2f, 0.2f, 0.2f));
		sbox->color(RGBAColor(1.0f,1.0f,1.0f));
	}

	else if(state==SUNSET_ENVIRON){
		Lighting::instance().globalAmbient(RGBAColor(0.2f, 0.0f, 0.0f, 1.0f));
		sbox->color(RGBAColor(1.0f,1.0f,1.0f));
	}

	else if(state==NIGHT_ENVIRON){
		RGBAColor(0.2f,0.4f,1.0f),
		Lighting::instance().globalAmbient(RGBAColor(0.1f, 0.2f, 0.4f, 1.0f));
		//Lighting::instance().globalAmbient(RGBAColor(1.0f, 1.0f, 1.0f, 1.0f));
		sbox->color(RGBAColor(1.0f,1.0f,1.0f));
	}

	else if(state==STORM_ENVIRON){
		Lighting::instance().globalAmbient(RGBAColor(0.6f, 0.6f, 0.6f, 1.0));
		sbox->color(RGBAColor(0.4f,0.4f,0.4f));
		rain->start();
	}

	else if(state==MNT_ENVIRON){
		Lighting::instance().globalAmbient(RGBAColor(0.2f, 0.2f, 0.2f, 0.2f));
		sbox->color(RGBAColor(1.0f,1.0f,1.0f));
	}
}

void SceneModel::createEnvironLights(){
	Light* dayLight1 = Lighting::instance().createLight(	Point(510,510,150),
															RGBAColor(0.0f,0.0f,0.0f),
															RGBAColor(1.0f,1.0f,1.0f),1.0f,0.006f);

	Light* dayLight2 = Lighting::instance().createLight(	Point(510,10,150),
															RGBAColor(0.0f,0.0f,0.0f),
															RGBAColor(1.0f,1.0f,1.0f),1.0f,0.006f);

	Light* dayLight3 = Lighting::instance().createLight(	Point(-10,-10,400),
															RGBAColor(1.0f,1.0f,1.0f),
															RGBAColor(0.0f,0.0f,0.0f));

	lights[DAY_ENVIRON].push_back(dayLight1);
	lights[DAY_ENVIRON].push_back(dayLight2);
	lights[DAY_ENVIRON].push_back(dayLight3);


	Light* sunsetLight1 = Lighting::instance().createLight(	Point(300,700,400),
															RGBAColor(0.6f,0.4f,0.3f),
															RGBAColor(1.0f,0.8f,0.7f));

	lights[SUNSET_ENVIRON].push_back(sunsetLight1);

	Light* nightLight1 = Lighting::instance().createLight(	Point(-1,1,-1,0),
															RGBAColor(0.2f,0.4f,1.0f),
															RGBAColor(0.2f,0.4f,1.0f));

	lights[NIGHT_ENVIRON].push_back(nightLight1);

	Light* mntLight1 = Lighting::instance().createLight(	Point(-1,-1,-1,0),
															RGBAColor(1.0f,1.0f,1.0f),
															RGBAColor(1.0f,1.0f,1.0f));

//	Light* mntLight1 = Lighting::instance().createLight(	Point(-10,-10,90,1),
//															RGBAColor(0.8f,0.8f,0.8f),
//															RGBAColor(0.8f,0.8f,0.8f));
//
//	Light* mntLight2 = Lighting::instance().createLight(	Point(600,600,80,1),
//															RGBAColor(0.8f,0.8f,0.8f),
//															RGBAColor(0.0f,0.0f,0.0f),0.0f,0.02f);

	lights[MNT_ENVIRON].push_back(mntLight1);
	//lights[MNT_ENVIRON].push_back(mntLight2);
}

void SceneModel::createTrees(){
	std::vector<Point> points;

	if(this->getEnvironState()==MNT_ENVIRON){
		parseDistFile((modelPath+"tree/mnt_tree_dist.data").c_str(),points);
	}else{
		parseDistFile((modelPath+"tree/tree_dist.data").c_str(),points);
	}

	unsigned int treeTypes = 3;
	Cube treeSizes[] = { 	Cube( Point(0,0,0),Point(4,4,8) ),
							Cube( Point(0,0,0),Point(4,4,10) ),
							Cube( Point(0,0,0),Point(3,3,7) ) };
	unsigned int treeSizesCount = 3;

	for(unsigned int c=0;c<points.size();c++){
		unsigned int sizeType = rand()%treeSizesCount;
		Cube tc = treeSizes[sizeType];
		tc.center(Point(points[c].x1,points[c].x2,points[c].x3));

		std::ostringstream tname;
		std::ostringstream name;
		unsigned int type = rand()%treeTypes;
		tname <<  "tree" << type << ".obj";

		FileModel* treeModel = new FileModel(modelPath+"tree/",tname.str());
		treeModel->loadModel();
		SceneObject::ObjectModelPtr treeModelPtr(treeModel);

		Tree* tree = new Tree(tc,treeModelPtr);

		name <<  Tree::name() << c;
		std::map<std::string,unsigned int>::iterator it=indices.find(name.str());
		if(it==indices.end()){
			this->objectList.push_back(tree);
			indices.insert(std::make_pair(name.str(),this->objectList.size()-1));
		}else{
			delete this->objectList[it->second];
			this->objectList[it->second]=tree;
		}
	}
}

void SceneModel::createPlatform(){
	FileModel* platformModel = new FileModel(modelPath+"plat/","plat.obj");
	platformModel->loadModel();
	SceneObject::ObjectModelPtr platformModelPtr(platformModel);

	Cube pCube(Point(180,180,0),Point(210,210,10));
	if(this->getEnvironState()==MNT_ENVIRON)
		pCube = Cube(Point(144,377,1.5),Point(174,407,11.5));

	pCube.translate(0,0,-5);
	BoxPlatform* platform = new BoxPlatform(pCube,platformModelPtr);


	std::map<std::string,unsigned int>::iterator it=indices.find(BoxPlatform::name());
	if(it==indices.end()){
		this->objectList.push_back(platform);
		indices.insert(std::make_pair(BoxPlatform::name(),this->objectList.size()-1));
	}else{
		gravity.removeSolid(dynamic_cast<Solid*>(this->objectList[it->second]));
		delete this->objectList[it->second];
		this->objectList[it->second]=platform;
	}

	this->gravity.addSolid(platform);
}

void SceneModel::createWarehouse(){
	FileModel* model = new FileModel(modelPath,"cube.obj");
	model->loadModel();
	SceneObject::ObjectModelPtr modelPtr(model);

	FileModel* depotModel = new FileModel(modelPath+"warehouse/","warehouse.obj");
	depotModel->loadModel();
	SceneObject::ObjectModelPtr depotModelPtr(depotModel);

	Cube wCube(Point(310.0f,310.0f,0.0f),Point(380.0f,380.0f,60.0f));
	if(this->getEnvironState()==MNT_ENVIRON){
		wCube = Cube(Point(300.0f,150.0f,2.0f),Point(360.0f,210.0f,52.9f));
	}
	Warehouse* warehouse = new Warehouse(wCube,depotModelPtr);

	std::map<std::string,unsigned int>::iterator it=indices.find(Warehouse::name());
	if(it==indices.end()){
		this->objectList.push_back(warehouse);
		indices.insert(std::make_pair(Warehouse::name(),this->objectList.size()-1));
	}else{
		delete this->objectList[it->second];
		this->objectList[it->second]=warehouse;
	}
}

void SceneModel::createLightPosts(){
	std::vector<Point> points;

	if(this->getEnvironState()==MNT_ENVIRON)
		parseDistFile((modelPath+"lightpost/mnt_lightpost_dist.data").c_str(),points);
	else
		parseDistFile((modelPath+"lightpost/lightpost_dist.data").c_str(),points);
	FileModel* lightPostModel = new FileModel(modelPath+"lightpost/","lightpost.obj");
	lightPostModel->loadModel();
	SceneObject::ObjectModelPtr lightPostModelPtr(lightPostModel);

	for(unsigned int c=0;c<points.size();c++){
		Cube lightPostCube = Cube( Point(0,0,0),Point(4,4,10) );
		lightPostCube.center(Point(points[c].x1,points[c].x2,points[c].x3));
		LightPost* lp = new LightPost(lightPostCube,lightPostModelPtr);

		std::ostringstream name;
		name << LightPost::name() << c;
		std::map<std::string,unsigned int>::iterator it=indices.find(name.str());
		if(it==indices.end()){
			this->objectList.push_back(lp);
			indices.insert(std::make_pair(name.str(),this->objectList.size()-1));
		}else{

			lights[NIGHT_ENVIRON].erase(std::find(	lights[NIGHT_ENVIRON].begin(),
													lights[NIGHT_ENVIRON].end(),
													dynamic_cast<LightPost*>(this->objectList[it->second])->light() ));
			lights[STORM_ENVIRON].erase(std::find(	lights[STORM_ENVIRON].begin(),
													lights[STORM_ENVIRON].end(),
													dynamic_cast<LightPost*>(this->objectList[it->second])->light() ));
			delete this->objectList[it->second];
			this->objectList[it->second]=lp;
		}

		lights[NIGHT_ENVIRON].push_back(lp->light());
		lights[STORM_ENVIRON].push_back(lp->light());
	}
}

void SceneModel::parsePathFile(Path& path,const std::string& fname,TruckPathInfo* &loadPathInfo,TruckPathInfo* &unloadPathInfo){
	// NO SE VERIFICAN INCONSISTENCIAS EN EL ARCHIVO
	std::ifstream file(fname.c_str());
	if(!file.is_open())
		throw SceneModelException("No se pudo abrir el archivo: " + fname);

	std::string line;
	// Header
	file >> line;
	if(line!="HEADER")
		throw -1;

	float accelUp=0,accelDown=0,maxSpeed=0,minSpeed=0;

	while(line!="DATA"){
		file>>line;
		if(line=="UP_ACCEL"){
			file >> line;
			accelUp=atof(line.c_str());
		}

		else if(line=="DOWN_ACCEL"){
			file >> line;
			accelDown=atof(line.c_str());
		}


		else if(line=="MAX_SPEED"){
			file >> line;
			maxSpeed=atof(line.c_str());
		}

		else if(line=="MIN_SPEED"){
			file >> line;
			minSpeed=atof(line.c_str());
		}

	}

	float val=0;
	while(!file.eof()){
		std::string cmd;
		file >> cmd;

		if(cmd=="ACCEL"){
			val=accelUp;
		}

		else if(cmd=="BRAKE"){
			val=-accelDown;
		}

		else if(cmd=="CONST_SPEED"){
			val=0;
		}

		else{
			std::string line;
			if(cmd=="LOAD_POINT" || cmd=="UNLOAD_POINT")
				file >> line;
			else
				line = cmd;


			std::size_t posX = line.find_first_of(",");
			float numberX = atof(line.substr(0,posX).c_str());
			std::size_t posY = line.find_first_of(",",posX+1);
			float numberY = atof(line.substr(posX+1,posY-posX-1).c_str());
			float numberZ = atof(line.substr(posY+1).c_str());

			if(cmd=="LOAD_POINT"){
				loadPathInfo = new TruckPathInfo(val,maxSpeed,minSpeed);
				path.push_back(PathData(Point(numberX,numberY,numberZ),loadPathInfo));
			}

			else if(cmd=="UNLOAD_POINT"){
				unloadPathInfo = new TruckPathInfo(val,maxSpeed,minSpeed);
				path.push_back(PathData(Point(numberX,numberY,numberZ),unloadPathInfo));
			}

			else{
				path.push_back(PathData(Point(numberX,numberY,numberZ),new TruckPathInfo(val,maxSpeed,minSpeed)));
			}
		}

		file.peek();
	}
}

void SceneModel::parseDistFile(const std::string& path,std::vector<Point>& points){
	// NO SE VERIFICAN INCOSISTENCIAS EN EL ARCHIVO
	std::ifstream file( path.c_str() );
	if(!file.is_open())
		throw SceneModelException("No se pudo abrir el archivo: " + path);

	while(!file.eof()){
		std::string line;
		file >> line;
		file.peek();

		if(!file.eof()){
			std::size_t posX = line.find_first_of(",");
			float numberX = atof(line.substr(0,posX).c_str());
			std::size_t posY = line.find_first_of(",",posX+1);
			float numberY = atof(line.substr(posX+1,posY-posX-1).c_str());
			std::size_t posZ = line.find_first_of(",",posY+1);
			float numberZ = atof(line.substr(posY+1,posZ-posY-1).c_str());

			points.push_back(Point(numberX,numberY,numberZ));
		}
	}
}
